<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>点缓冲矩形</title>
  <link rel="stylesheet" href="http://js.arcgis.com/4.14/esri/css/main.css">
  <script src="js/jquery-1.12.4.js"></script>
  |
  <script src="http://js.arcgis.com/4.14/"></script>
  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }

    * {
      margin: 0;
      padding: 0;
    }

    .btn-box {
      position: absolute;
      top: 110px;
      left: 5px;
    }

    ul {
      list-style: none;
      position: relative;
      border-radius: 5px;
      box-shadow: 0 0 rgb(233, 233, 233);
    }

    li {
      padding: 10px;
      height: 22px;
      line-height: 22px;
      font-size: 0;
      background-color: white;
    }

    span {
      display: inline-block;
      width: 22px;
      height: 22px;
      line-height: 22px;
      float: left;
      color: black;
      font-size: 14px;
    }

    li input {
      float: left;
      vertical-align: top;
      height: 22px;
      line-height: 22px;
      display: inline-block;
      font-size: 14px;
    }

    .tip_msg {
      position: absolute;
      display: none;
      top: -100px;
      left: -100px;
      height: 20px;
      line-height: 20px;
      padding: 5px 3px;
      font-size: 14px;
      background-color: white;
      color: black;
      font-family: "微软雅黑";
      text-align: center;
      border-radius: 5px;
      box-shadow: 0 0 -1 rgb(233, 233, 233);
    }
  </style>
</head>

<body>
  <div id="viewDiv">
  </div>
  <div class="btn-box">
    <ul>
      <li>
        <button class="choose_location">选择点位</button>
      </li>
      <li>
        <span>长:</span><span class="txt_wd" style="width: 40px;">1000</span><input class="wd" type="range" value="1000"
          min="800" max="2000">
      </li>
      <li>
        <span>宽: </span><span class="txt_hg" style="width: 40px;">800</span><input class="hg" type="range" value="800"
          min="600" max="1600">
      </li>
    </ul>
  </div>
  <div class="tip_msg">请在地图上单击选择点位</div>



  <script>
    $(function () {
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/views/SceneView",
        "esri/views/draw/Draw",
        "esri/layers/GraphicsLayer",
        "esri/Graphic",
        "esri/geometry/Polyline",
        "esri/geometry/Polygon",
        "esri/geometry/Point",
        "esri/geometry/Circle",
        "esri/geometry/geometryEngine",
        "esri/geometry/support/webMercatorUtils",
        "esri/widgets/Measurement",
        "dojo/domReady!"
      ], function (
        Map, MapView, SceneView,
        GraphicsLayer,
        Draw, Graphic,
        Polyline, Polygon, Point, Circle,
        geometryEngine, webMercatorUtils, Measurement
      ) {

        var wd = $(".wd").val();
        var hg = $(".hg").val();
        var rectangelGp = null,
          curMoveGraphic = null,
          moveGp = null,
          scaleGp = null;
        var setLocation = false;
        var moveMapPoint = null;

        var map = new Map({
          basemap: "dark-gray"
        });

        //二维视图
        var view = new MapView({
          map: map,
          container: "viewDiv",
          center: [112.23, 23.34],
          zoom: 18
        });
        console.log(map)

        var measurement = new Measurement({
          view: view,
          activeTool: "distance"
        })
        view.ui.add(measurement, "top-right")

        view.when(function () {
          view.on("click", function (event) {
            //设置点位
            if (setLocation) {
              view.graphics.removeAll();
              var symbol = {
                type: "simple-marker",
                color: [255, 0, 0, 0.8]
              }
              //中心点图形
              var gp = new Graphic({
                geometry: moveMapPoint,
                symbol: symbol
              })
              //生成矩形图形
              rectangelGp = getRectangleBuffer([moveMapPoint.longitude, moveMapPoint.latitude], wd, hg);
              view.graphics.add(rectangelGp, 0)
              view.graphics.add(gp)
              setLocation = false;
              //关闭提示
              closeTip();
            }
          })

          view.on("pointer-move", function (event) {
            if (setLocation) {
              view.graphics.removeAll()
              moveMapPoint = view.toMap({
                x: event.x,
                y: event.y
              })
              var moveSymbol = {
                type: "simple-marker",
                color: [288, 288, 288, 0.8]
              }
              moveGp = new Graphic({
                geometry: moveMapPoint,
                symbol: moveSymbol
              })
              view.graphics.add(moveGp)
              openTip({
                x: event.x,
                y: event.y
              })
            }
          })

          $(".choose_location").on("click", function () {
            setLocation = true;
          })

          view.on("drag", function (event) {
            var clk_event = event;
            if (!rectangelGp || !curMoveGraphic) return;
            if (event.action == "start") {
              $("#view").css("cursor", "move")
              view.hitTest(event).then(function (response) {
                if (response.results[0].graphic.attributes.name == "rectangleGp") {
                  curMoveGraphic = response.results[0].graphic;
                  event.stopPropagation(); // 拖动时阻止地图的拖动
                }
              });
            }
            //update
            if (event.action == "end") {
              $("#view").css("cursor", "")
            }
            if (event.action == "update") {
              $("#view").css("cursor", "move")
              event.stopPropagation();
              var geometry = view.toMap({
                x: event.x,
                y: event.y,
              });
              curMoveGraphic.geometry = geometry;
              //更新矩形各顶点
              updateRectangleGp(curMoveGraphic)
            }
          })

          $(".wd").on("input propertychange", function () {
            wd = $(this).val()
            $(".txt_wd").html(wd)
            if (!rectangelGp) return;
            view.graphics.remove(rectangelGp);
            view.graphics.remove(scaleGp);
            rectangelGp = getRectangleBuffer([moveMapPoint.longitude, moveMapPoint.latitude], wd, hg);
            view.graphics.add(rectangelGp, 0)
          })

          $(".hg").on("input propertychange", function () {
            hg = $(this).val()
            $(".txt_hg").html(hg)
            if (!rectangelGp) return;
            view.graphics.remove(rectangelGp);
            view.graphics.remove(scaleGp);
            rectangelGp = getRectangleBuffer([moveMapPoint.longitude, moveMapPoint.latitude], wd, hg);
            view.graphics.add(rectangelGp, 0)
          })

          function openTip(screenPoint) {
            $(".tip_msg").css({
              "display": "block",
              "top": screenPoint.y - $(".tip_msg").height() + "px",
              "left": screenPoint.x - $(".tip_msg").width() / 2 + "px"
            })
          }

          function closeTip() {
            $(".tip_msg").css({
              "display": "none",
              "top": "-100px",
              "left": "-100px"
            })
          }

          /**
           * 绘制长方形缓冲的方法
           * 中心点-[lon,lat]
           * 长-width
           * 宽-height 
           */
          function getRectangleBuffer(centerPt, width, height) {
            var xieLineDis = Math.sqrt(width * width + height * height);
            var Tdegs = deg(Math.atan(width / height)); //弧度转换为度数
            var coordTopLeft = distanceAngle({ lon: centerPt[0], lat: centerPt[1] }, -Tdegs, xieLineDis / 2); //左上角坐标
            var coordTopRight = distanceAngle({ lon: centerPt[0], lat: centerPt[1] }, Tdegs, xieLineDis / 2); //右上角
            var coordBottomLeft = distanceAngle({ lon: centerPt[0], lat: centerPt[1] }, -(180 - Tdegs), xieLineDis / 2); //左下角
            var coordBootomRight = distanceAngle({ lon: centerPt[0], lat: centerPt[1] }, 180 - Tdegs, xieLineDis / 2); //右下角
            //构建一个polygon所需的环形数组
            var points = [
              [coordTopLeft.lon, coordTopLeft.lat],
              [coordTopRight.lon, coordTopRight.lat],
              [coordBootomRight.lon, coordBootomRight.lat],
              [coordBottomLeft.lon, coordBottomLeft.lat]
            ]
            //右上角的点，用来同步放大矩形
            var scalePt = new Point({
              longitude: coordTopRight.lon,
              latitude: coordTopRight.lat,
              spatialReference: view.spatialReference
            })
            var scaleSym = {
              type: "simple-marker",
              color: [266, 266, 266, 0.8]
            }
            scaleGp = new Graphic({
              geometry: scalePt,
              symbol: scaleSym,
              attributes: {
                name: "rectangleGp"
              }
            })
            view.graphics.add(scaleGp)
            var polygon = new Polygon({
              rings: points
            })
            var recsymbol = {
              type: "simple-fill",
              color: [267, 267, 0]
            }
            var rectangleGp = new Graphic({
              geometry: polygon,
              symbol: recsymbol
            })
            return rectangleGp;
          }

          function updateRectangleGp(curMoveGraphic) {
            var xDiff = curMoveGraphic.geometry.longitude - rectangelGp.geometry.rings[0][1][0];
            var yDiff = curMoveGraphic.geometry.latitude - rectangelGp.geometry.rings[0][1][1];
            var clone_rectangleGp = rectangelGp.geometry.clone();
            clone_rectangleGp.rings[0][0][0] -= xDiff;
            clone_rectangleGp.rings[0][0][1] += yDiff;
            clone_rectangleGp.rings[0][1][0] += xDiff;
            clone_rectangleGp.rings[0][1][1] += yDiff;
            clone_rectangleGp.rings[0][2][0] += xDiff;
            clone_rectangleGp.rings[0][2][1] -= yDiff;
            clone_rectangleGp.rings[0][3][0] -= xDiff;
            clone_rectangleGp.rings[0][3][1] -= yDiff;
            rectangelGp.geometry = clone_rectangleGp;
          }

          /**
           * 度换成弧度
           * @param  {Float} d  度
           * @return {[Float}   弧度
           */
          function rad(d) {
            return d * Math.PI / 180.0;
          }

          /**
           * 弧度换成度
           * @param  {Float} x 弧度
           * @return {Float}   度
           */
          function deg(x) {
            return x * 180 / Math.PI;
          }

          function distanceAngle(lonlat, brng, dist) {
            var u = this;
            var ct = {
              a: 6378137,
              b: 6356752.3142,
              f: 1 / 298.257223563
            };
            var a = ct.a, b = ct.b, f = ct.f;

            var lon1 = lonlat.lon * 1;
            var lat1 = lonlat.lat * 1;

            var s = dist;
            var alpha1 = rad(brng);
            var sinAlpha1 = Math.sin(alpha1);
            var cosAlpha1 = Math.cos(alpha1);

            var tanU1 = (1 - f) * Math.tan(rad(lat1));
            var cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;
            var sigma1 = Math.atan2(tanU1, cosAlpha1);
            var sinAlpha = cosU1 * sinAlpha1;
            var cosSqAlpha = 1 - sinAlpha * sinAlpha;
            var uSq = cosSqAlpha * (a * a - b * b) / (b * b);
            var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
            var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));

            var sigma = s / (b * A), sigmaP = 2 * Math.PI;
            while (Math.abs(sigma - sigmaP) > 1e-12) {
              var cos2SigmaM = Math.cos(2 * sigma1 + sigma);
              var sinSigma = Math.sin(sigma);
              var cosSigma = Math.cos(sigma);
              var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
                B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
              sigmaP = sigma;
              sigma = s / (b * A) + deltaSigma;
            }

            var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
            var lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
              (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
            var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
            var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
            var L = lambda - (1 - C) * f * sinAlpha *
              (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
            var revAz = Math.atan2(sinAlpha, -tmp);  // final bearing
            var lon_destina = lon1 * 1 + deg(L);
            var lonlat_destination = { lon: lon_destina, lat: deg(lat2) };

            return lonlat_destination;
          }

        })
      })
    })
  </script>
</body>

</html>